package svm;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import svm.Session.Activity;
import svm.Session.SessionFrame;
import utils.Logger;
import utils.Utils;
import au.AU;
import au.AU.Label;

public class Interval {

	private HashMap<Label, Double> avgAus = new HashMap<Label, Double>();
	private int fromFrame;
	private int toFrame;
	private Session luxandData;
	private List<Activity> activities = new ArrayList<Activity>();

	private Interval(Session luxandData, int fromFrame, int toFrame, HashMap<Label, Double> recognizedAus) {
		this.fromFrame = fromFrame;
		this.toFrame = toFrame;
		this.luxandData = luxandData;
		this.avgAus = recognizedAus;
		Date from = luxandData.getSessionFrames().get(fromFrame).time;
		Date to = luxandData.getSessionFrames().get(toFrame).time; 
		for(Activity act: luxandData.getActivityList()) {
			if(act.time.compareTo(from) >= 0 && act.time.compareTo(to) <= 0) this.activities.add(act);
		}
	}

	/**
	 * Factory method, creates list of instances for given window length.
	 * */
	public static List<Interval> createIntervals(Session luxandData,
			int winLength) {
		
		if(!luxandData.isRecognized()) {
			Logger.log("Interval", "Session " + luxandData.getSessionName() + " not recognized for AUs");
			return null;
		}
		
		List<Interval> list = new ArrayList<Interval>(); // result
		HashMap<Label, double[]> avgs = new HashMap<Label, double[]>(); // temporary storage for AU level value for the actual window used for average calculation
		
		for (AU.Label label : AU.Label.values())
			avgs.put(label, new double[winLength]);

		for (int window = 0; window < luxandData.getSessionFrames().size() / winLength; window++) {
			
			int fromFrame = window * winLength;
			int toFrame = fromFrame + winLength - 1;
			
			// collects values for average AU level within the actual window for each label
			for (int i = 0; i < winLength; i++) { // for each frame in the window
				int luxandDataIndex = fromFrame + i;
				if (luxandData.getSessionFrames().size() > luxandDataIndex) {
					for (AU.Label label : AU.Label.values()) { // for each label
						avgs.get(label)[i] = luxandData.getSessionFrames().get(luxandDataIndex).getRecognizedAU(label); // TODO test for 'null' level
					}
				}
			}
			
			// calculates and puts into interval average AU levels for each label
			HashMap<Label, Double> avgAUs = new HashMap<Label, Double>();
			for (AU.Label label : AU.Label.values()) {
				//System.out.println("ARRAY: " + avgs.get(label));
				double avgAU = Utils.avg(avgs.get(label));
				avgAUs.put(label, avgAU);
			}
			
			Interval interval = new Interval(luxandData, fromFrame, toFrame, avgAUs);
			list.add(interval);
			
		}
		return list;
	}
	
	@Override
	public String toString() {
		return new String("Interval <" + fromFrame + "," + toFrame + ">; AVG AUs " + avgAus.toString() );
	}
	
	public File getLuxandDataFile() {
		return luxandData.getLuxandDataFile();
	}
	
	public List<SessionFrame> getRows() {
		return this.luxandData.getSessionFrames().subList(fromFrame, toFrame);
	}

	public List<Activity> getActivities() {
		return activities;
	}

	public double getAvgAu(AU.Label label) {
		return this.avgAus.get(label);
	}
}
